#include "crossbit/common.h"
//#include "fcntl.h"
//#include "signal.h"
//#include "sys/time.h"
//#include "sys/wait.h"
//#include "sys/resource.h"
//#include "crossbit/Interpreter.h"
//#include "crossbit/MemoryImage.h"
//#include "crossbit/ELFMemoryImage.h"
#include "crossbit/SYSCALL.h"

using namespace crossbit;


// Implementation related header info
#include "arch/mips/MIPSSignalRegister.h"

XTInt32 MIPSSignalRegister::regSignalHandler(XTInt32 mips_sig_num, XTMemAddr mips_sig_h)
{
        UTIL::XTLOG("regSigHandler is invoked\n");
        UTIL::XTExit(-1);
}

XTInt32 MIPSSignalRegister::regRTSignalHandler(XTInt32 mips_sig_num, XTMemAddr mips_rt_sig_h)
{
        UTIL::XTLOG("regRTSigHandler is invoked\n");
        UTIL::XTExit(-1);
}

XTInt32 MIPSSignalRegister::regSigactionHandler(XTInt32 mips_sig_num, XTMemAddr mips_act, XTMemAddr mips_oldact)
{
        UTIL::XTLOG("regSigactionHandler is invoked\n");
        UTIL::XTExit(-1);
}

XTInt32 MIPSSignalRegister::regRTSigactionHandler(XTInt32 mips_sig_num, XTMemAddr mips_act, XTMemAddr mips_oldact)
{

		XTInt32 local_sig_num = convertSigNum2Host(mips_sig_num);

		if (UNDEF == local_sig_num)
		{
			errno = EINVAL;
			return -1;
		}
	
		struct sigaction *act, *oact;
		struct sigaction local_act, local_oact;


		// FIXME:  We only support to register one parameter handler func.
		// On MIPS, it seem only support this kind signal func.
		// So in this register procedure, we set SA_SIGINFO unavailible and register corresponding handler only.
		if(!mips_act)
			act = NULL;
		else
		{
			act = &local_act;
			struct mips_sigaction *mips_sigact = (struct mips_sigaction*)mips_act;
			mips__sighandler_t mips_hdler = mips_sigact->sa_hdler;	// FIXME: should be modified for sa_sigaction handler
		
			XTInt32 i = 0;
			for ( ; i<MIPS_FNTBL_SZ; i++)
			{
					if (mips_hdler == sh_fn_table[i].mips_fn)
					{
						local_act.sa_handler = sh_fn_table[i].local_fn;
						break;
					}
			}

			if (i >= MIPS_FNTBL_SZ ){
				setHandlerSPC(mips_sig_num, (XTMemAddr)mips_hdler);

				if ((mips_sigact->sa_flags) & MIPS_SA_SIGINFO)
					local_act.sa_sigaction = (mips_sa_sigaction) rt_sigaction_handler;	//FIXME: reserved for handler like sa_sigaction with 3 parameters
																						// mips_sa_sigaction should be changed to local type
				else
					local_act.sa_handler = (sighandler_t) rt_signal_handler;
			}

			local_act.sa_flags = convertSaFlags2Host(mips_sigact->sa_flags);

			convertSaMask2Host((XTUint32*)&(mips_sigact->sa_mask),(XTUint32*)&(local_act.sa_mask));	
		}

		if(!mips_oldact)
			oact = NULL;
		else
		{
			oact = &local_oact;
			struct mips_sigaction *mips_oldsigact = (struct mips_sigaction*)mips_oldact;
			mips__sighandler_t mips_oldhdler = mips_oldsigact->sa_hdler;	// FIXME: should be modified for sa_sigaction handler
		
			XTInt32 i = 0;
			for ( ; i<MIPS_FNTBL_SZ; i++)
			{
					if (mips_oldhdler == sh_fn_table[i].mips_fn)
					{
						local_oact.sa_handler = sh_fn_table[i].local_fn;
						break;
					}
			}

			if (i >= MIPS_FNTBL_SZ ){
				if ((mips_oldsigact->sa_flags) & MIPS_SA_SIGINFO)
					local_oact.sa_sigaction = (mips_sa_sigaction) rt_sigaction_handler;	//FIXME: reserved for handler like sa_sigaction with 3 parameters
																						// mips_sa_sigaction should be changed to local type
				else
					local_oact.sa_handler = (sighandler_t) rt_signal_handler;
			}

			local_oact.sa_flags = convertSaFlags2Host(mips_oldsigact->sa_flags);

			convertSaMask2Host((XTUint32*)&(mips_oldsigact->sa_mask),(XTUint32*)&(local_oact.sa_mask));	
		}

		//UTIL::XTLOG("mips    mask: %x\n",((struct mips_sigaction*)mips_act)->sa_mask);
		//UTIL::XTLOG("local   mask: %x\n",act->sa_mask);
		//UTIL::XTLOG("mips  signum: %x\n",mips_sig_num);
		//UTIL::XTLOG("local signum: %x\n",local_sig_num);

        return SYSCALL::XTSigaction(local_sig_num, act, oact);

}


XTInt32 MIPSSignalRegister::convertSigNum2Host(XTInt32 mips_sig_num)	// if sig_num > MIPS_SIGRTMIN, mips_sig = local_sig
{
	if (mips_sig_num > SIGRTMAX)
		return UNDEF;
	if (mips_sig_num > MIPS_SIGRTMIN)
		return mips_sig_num;
	for (XTInt32 i=0; sig_table[i].mips_flag; i++)
	{
		if (mips_sig_num == sig_table[i].mips_flag)
			return sig_table[i].local_flag;
	}
	return UNDEF;
}

XTUint32 MIPSSignalRegister::convertSaFlags2Host(XTUint32 mips_sa_flags)
{
	XTUint32 local_flags = 0x0UL;
	for (XTInt32 i=0; sa_flag_table[i].mips_flag; i++)
	{
		if (mips_sa_flags & (sa_flag_table[i].mips_flag))
			local_flags |= (sa_flag_table[i].local_flag);
	}
	return local_flags;
	//return (local_flags & (~(SA_SIGINFO)));		// FIXME: On mips, only support one parameter handler
												// Maybe we can not support SA_ONSTACK also.
}

void MIPSSignalRegister::convertSaMask2Host(XTUint32 *mips_sa_mask, XTUint32 *local_sa_mask)
{
	XTInt32 mask_set_num = ((sizeof(sigset_t)< sizeof(mips_sigset_t)) ? sizeof(sigset_t) : sizeof(mips_sigset_t)) / sizeof(XTInt32);

	UTIL::XTMemset((void*)local_sa_mask, 0, sizeof(sigset_t));

	for (XTInt32 i=1; i<mask_set_num; i++)
		*(local_sa_mask+i) = *(mips_sa_mask+i);

	XTUint32 mips_low_set = *mips_sa_mask;

	for (XTInt32 j=0; sig_table[j].mips_flag; j++)
	{
		if (((0x1UL<<(sig_table[j].mips_flag-1UL)) & mips_low_set) && (sig_table[j].local_flag))
			(*local_sa_mask) |= (0x1UL<<(sig_table[j].local_flag-1UL));
	}
	
}

XTInt32 MIPSSignalRegister::convertSbHow2Host(XTInt32 mips_sb_how)
{	
	for (XTInt32 i=0; sb_flag_table[i].mips_flag; i++)
	{
		if (mips_sb_how == sb_flag_table[i].mips_flag)
			return sb_flag_table[i].local_flag;
	}
	return UNDEF;
}
